package com.kehutong.charge.service.impl;

import com.kehutong.charge.dto.InterimBillImportDTO;
import com.kehutong.charge.entity.*;
import com.kehutong.charge.util.CommonClient;
import com.kehutong.charge.util.ConvertUtil;
import com.kehutong.charge.dto.ChargeStatistDTO;
import com.kehutong.charge.service.ChargeBillInterimService;
import com.kehutong.charge.service.CommonService;
import com.kehutong.charge.util.CommonUtil;
import com.kehutong.charge.util.enums.ChargeBillStatusEnum;
import com.kehutong.charge.util.enums.ChargeLogEnum;
import com.kehutong.charge.util.enums.ResidentsTypeEnum;
import com.kehutong.charge.vo.InterimBillTemplateExcelVO;
import com.kehutong.common.DeptService;
import com.kehutong.common.DoveClient;
import com.kehutong.common.constant.RegexConstant;
import com.kehutong.common.dto.DeptDTO;
import com.kehutong.common.enums.UserType;
import com.kehutong.common.errcode.Assert;
import com.kehutong.common.excel.entity.ImportResult;
import com.kehutong.common.excel.tool.ExcelTool;
import com.kehutong.common.util.ConvertUtils;
import com.kehutong.common.util.BigDecimalUtils;
import com.kehutong.common.util.ListUtils;
import com.kehutong.common.errcode.Result;
import com.kehutong.common.util.Token;
import org.coraframework.bean.Beans;
import org.coraframework.converter.util.StringUtil;
import org.coraframework.inject.Inject;
import org.coraframework.json.JSONArray;
import org.coraframework.json.JSONObject;
import org.coraframework.logger.Logger;
import org.coraframework.logger.LoggerFactory;
import org.coraframework.orm.Pool;
import org.coraframework.orm.jdbc.JdbcSession;
import org.coraframework.orm.jdbc.Page;
import org.coraframework.orm.jdbc.execute.entity.FindPage;
import org.coraframework.util.Objects;
import org.coraframework.util.time.TimeUtil;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @program: kht
 * @description: ChargeBillInterimServiceImpl
 * @author: joneron
 * @create: 2021/7/5
 **/
public class ChargeBillInterimServiceImpl implements ChargeBillInterimService {

    private static final Logger logger = LoggerFactory.getLogger(ChargeBillInterimServiceImpl.class);
    private static List<InterimBillTemplateExcelVO> template = new ArrayList<>();
    static {
        InterimBillTemplateExcelVO vo = new InterimBillTemplateExcelVO();
        vo.setCommunityName("七星小区（示例）");
        vo.setBuildName("1栋");
        vo.setUnitName("1单元");
        vo.setHouseNumber("1001");
        vo.setFeeTypeName("装修押金");
        vo.setBillAmount("200");
        vo.setBillState("未缴费");
        vo.setMobile("13232333333");
        vo.setRemarks("1栋1单元1001装修押金");
        template.add(vo);
    }


    @Inject
    private JdbcSession jdbcSession;
    @Inject
    CommonService commonService;
    @Inject
    ExcelTool excelTool;
    @Inject
    DoveClient doveClient;
    @Inject
    DeptService deptService;
    @Inject
    CommonClient commonClient;


    @Override
    public Page<ChargeBillInterim> findPage(JSONObject jsonObject) {
        String search = jsonObject.getString("search");

        FindPage<ChargeBillInterim> find = jdbcSession.findPage(ChargeBillInterim.class)
                .eq("deleted", false)
                .like(jsonObject,"billYearMonth")
                .eq(jsonObject,"userNo")
                .eq(jsonObject,"communityNo")
                .eq(jsonObject,"feeTypeNo")
                .eq(jsonObject,"billStatus")
                .eq(jsonObject,"chargeStatus")
                .like(jsonObject,"interimBillNo");

        Token token = jsonObject.getObject("token", Token.class);
        logger.info("【临时缴费列表】--> token:{},jsonObject:{}",token);

        if(null != token && token.getUserType().equals(UserType.webwork)){
            try {
                logger.info("【临时缴费列表】 token:{},userType:{}",token.getUuid(),token.getUserType());
                JSONArray stewardHouseNos = commonClient.getStewardCommunity(token.getUuid());
                find.in("communityNo",stewardHouseNos);
                logger.info("【临时缴费列表】 stewardHouseNos:",stewardHouseNos);

            } catch (Exception e) {
                logger.error("获取管家楼栋异常");
                throw new RuntimeException(e);
            }
        }else {
            find.eq(jsonObject,"communityNo");
        }

        //添加选中导出条件
        JSONArray exportIdList = jsonObject.getJSONArray("exportIdList");
        if(!Objects.isEmpty(exportIdList)){
            find.in("interimBillNo",exportIdList);
        }
        if(!Objects.isEmpty(search)){
            find.markBegin();
            find.like("communityName", search).or();
            find.like("chargeName", search).or();
            find.markEnd();
        }
        find.order("createTime", "desc");
        find.page(jsonObject);
        return find.exe();
    }


    @Override
    public void pageExport(HttpServletRequest req, HttpServletResponse resp, JSONObject jsonObject) {
        jsonObject.put("pageNo", 1);
        jsonObject.put("pageSize", ExcelTool.MAX_ROWS);
        List<ChargeBillInterim> list = findPage(jsonObject).getList();
        Assert.notEmpty(list,"导出失败！没有找到临时收费账单相关数据.");
        List<InterimBillTemplateExcelVO> dtoList = ListUtils.copyList(list, InterimBillTemplateExcelVO::new);

        List<Map<String,Object>> houseList = null;
        try {
            Set<String> ids = dtoList.stream().map(l -> l.getHouseNo()).collect(Collectors.toSet());
            JSONObject param = new JSONObject();
            param.put("ids",ids);
            houseList = commonClient.getHouseByIds(param);
        } catch (Exception e) {
            logger.error("抄表导出获取房屋信息错误",e);
            excelTool.excelDownload(req,resp,dtoList,"临时收费账单列表导出");
        }
        List<Map<String, Object>> finalHouseList = houseList;
        dtoList.stream().map(r-> finalHouseList.stream().filter(h->h.get("id").equals(r.getHouseNo())).findFirst().map(h->{
            r.setCommunityName(ConvertUtils.toNoNullString(h.get("communityName")));
            r.setBuildName(ConvertUtils.toNoNullString(h.get("buildName")));
            r.setUnitName(ConvertUtils.toNoNullString(h.get("unitName")));
            r.setHouseNumber(ConvertUtils.toNoNullString(h.get("mergeName")));
            return r;
        }).orElse(null)).filter(java.util.Objects::nonNull).collect(Collectors.toList());

        excelTool.excelDownload(req,resp,dtoList,"临时收费账单列表导出");
    }


    @Override
    public void templateExport(HttpServletRequest req, HttpServletResponse resp) {
        excelTool.excelDownload(req, resp, template, "临时收费账单导入模板");
    }

    @Override
    public void importExcelCheck(JSONObject jsonObject) {
        excelTool.excelImport(jsonObject, InterimBillImportDTO.class);
    }


    /**
     * 导入临时账单
     * @param jsonObject
     * @param token
     * @return
     * @throws Exception
     */
    @Override
    public Object importExcel(JSONObject jsonObject, Token token) throws Exception {
        //初始化excel数据开始的行数，为每个数据添加下标
        Integer[] arr = {3};
        List<InterimBillImportDTO> dtoList = excelTool.excelImport(jsonObject, InterimBillImportDTO.class);
        dtoList = dtoList.stream().peek(d->d.setIndex(arr[0]++)).collect(Collectors.toList());

        int importTotal = dtoList.size();
        StringBuilder errorMsg = new StringBuilder();

        Set<String> importMobileSet = dtoList.stream().map(d -> d.getMobile().trim()).collect(Collectors.toSet());
        //校验手机号格式
        Set<String> unRegexSet = new HashSet<>(importMobileSet);
        unRegexSet.removeIf(m->RegexConstant.MOBILE_REGEX.matcher(m).find());
        if(!Objects.isEmpty(unRegexSet)){
            List<Integer> errorIndex = dtoList.stream().filter(d -> unRegexSet.contains(d.getMobile()))
                    .map(d -> d.getIndex()).collect(Collectors.toList());

            errorMsg.append(String.format("第%s行,[缴费人手机号]格式错误请检查.\n", errorIndex));
            ImportResult errResult = getImportResult(dtoList, importTotal, errorMsg, errorIndex);
            if (errResult != null) {return errResult;}
        }
        //校验手机号是否存在对应的住户
        List<Map<String, Object>> residentList = commonClient.getResidentListByMobiles(importMobileSet);

        //小区名称、楼栋、单元、房号
        Set<String> importBuildSet = dtoList.stream().map(d -> d.getBuildName().trim()).collect(Collectors.toSet());
        Set<String> importCommunitySet = dtoList.stream().map(d -> d.getCommunityName().trim()).collect(Collectors.toSet());
        Set<String> houseNumberSet = dtoList.stream().map(d -> d.getHouseNumber().trim()).collect(Collectors.toSet());
        Set<String> importUnitNameSet = dtoList.stream().map(d -> d.getUnitName()).collect(Collectors.toSet());
        importUnitNameSet.removeAll(Collections.singleton(null));

        JSONObject json = new JSONObject();
        json.put("communitySet",importCommunitySet);
        json.put("buildSet",importBuildSet);
        json.put("houseNumberSet",houseNumberSet);
        json.put("unitNameSet",importUnitNameSet);
        List<ChargeHouseConfig> dbHouseList = commonClient.getResidentListByMultipleQuery(json);
        if(Objects.isEmpty(dbHouseList)){
            errorMsg.append("导入的[小区名称]、[楼栋]、[单元](非必填)、[房号]无法匹配到住户信息.");
            return excelTool.R(importTotal,0,errorMsg.toString());
        }

        //费用类型
        Set<String> importFeeTypeSet = dtoList.stream().map(d -> d.getFeeTypeName().trim()).collect(Collectors.toSet());
        List<ChargeTypeTemp> dbFeeTypeList = jdbcSession.findArray(ChargeTypeTemp.class)
                .eq("deleted", false)
                .eq("status", true)
                .in("feeTypeName", importFeeTypeSet)
                .exe();
        if(Objects.isEmpty(dbFeeTypeList)){
            errorMsg.append("导入的[费用类型]系统中均未找到.");
            return excelTool.R(importTotal,0,errorMsg.toString());
        }
        Set<String> dbFeeTypeNames = dbFeeTypeList.stream().map(d -> d.getFeeTypeName().trim()).collect(Collectors.toSet());
        List<Integer> notFeeTypes = dtoList.stream().filter(d -> !dbFeeTypeNames.contains(d.getFeeTypeName()))
                .map(d -> d.getIndex()).collect(Collectors.toList());

        if(!Objects.isEmpty(notFeeTypes)){
            errorMsg.append(String.format("第%s行,[费用类型]在系统中未找到.\n", notFeeTypes));
            ImportResult errResult = getImportResult(dtoList, importTotal, errorMsg, notFeeTypes);
            if (errResult != null) {return errResult;}
        }
        //校验金额
        Set<String> importAmountSet = dtoList.stream().map(d -> d.getBillAmount().trim()).collect(Collectors.toSet());
        Set<String> unRegexAmountSet = new HashSet<>(importAmountSet);
        unRegexAmountSet.removeIf(m->RegexConstant.MONEY_REGEX.matcher(m).find());
        if(!Objects.isEmpty(unRegexAmountSet)){
            List<Integer> errorAmount = dtoList.stream().filter(d -> unRegexAmountSet.contains(d.getBillAmount()))
                    .map(d -> d.getIndex()).collect(Collectors.toList());

            errorMsg.append(String.format("第%s行,[收费金额]错误，金额只能是数字.\n", errorAmount));
            ImportResult errResult = getImportResult(dtoList, importTotal, errorMsg, errorAmount);
            if (errResult != null) {return errResult;}
        }

        List<Integer> errLessAmount = dtoList.stream().filter(d -> BigDecimalUtils.isLessThan(new BigDecimal(d.getBillAmount()), BigDecimal.ZERO))
                .map(d -> d.getIndex()).collect(Collectors.toList());
        if(!Objects.isEmpty(errLessAmount)){
            errorMsg.append(String.format("第%s行,[收费金额]错误，金额不能小于零.\n", errLessAmount));
            ImportResult errResult = getImportResult(dtoList, importTotal, errorMsg, errLessAmount);
            if (errResult != null) {return errResult;}
        }

        //缴费状态
        Set<String> importStateSet = dtoList.stream().map(d -> d.getBillStatus().trim()).collect(Collectors.toSet());
        List<String> notFindStateList = new ArrayList<>();
        importStateSet.forEach(it->{
            if(Objects.isEmpty(ChargeBillStatusEnum.getEnumId(it))){
                notFindStateList.add(it);
            }
        });
        if(!Objects.isEmpty(notFindStateList)){
            List<Integer> errIndex = dtoList.stream().filter(d -> notFindStateList.contains(d.getBillStatus()))
                    .map(d -> d.getIndex()).collect(Collectors.toList());

            errorMsg.append(String.format("第%s行,[缴费状态]系统中不存在，请查看首行导入说明后再填写状态名称.\n", errIndex));
            ImportResult errResult = getImportResult(dtoList, importTotal, errorMsg, errIndex);
            if (errResult != null) {return errResult;}
        }
        //操作人信息-----------------------------------------------------------------------------------------------
        String departmentNo = null;
        List<String> departmentNos = null;
        String departmentName = null;
        List<String> departList = token.getDepartments();
        String username = token.getUsername();
        if (!Objects.isEmpty(departList)) {
            DeptDTO dept = deptService.getDept(departList.get(0));
            departmentNo = dept.getDepartmentNo();
            departmentName = dept.getDepartmentName();
            departmentNos = dept.getDepartmentNos();
        }

        //orm
        List<ChargeBillInterim> ormList = new ArrayList<>();
        for(Iterator<InterimBillImportDTO> i = dtoList.iterator(); i.hasNext(); ) {
            InterimBillImportDTO importDTO = i.next();

            //格式统一化
            String buildName = importDTO.getBuildName();
            if(!Objects.isEmpty(buildName) && !buildName.contains("栋")){
                importDTO.setBuildName(buildName+"栋");
            }
            String unitName = importDTO.getUnitName();
            if(!Objects.isEmpty(unitName) && !unitName.contains("单元")){
                importDTO.setUnitName(unitName+"单元");
            }

            List<Integer> index = new ArrayList<>();
            index.add(importDTO.getIndex());

            ChargeBillInterim billInterim = Pool.newInstance(ChargeBillInterim.class);
            Beans.from((JSONObject) JSONObject.toJSON(importDTO)).to(billInterim).igornNull().copy();

            String address = ConvertUtil.jointAddress(importDTO.getCommunityName()
                    , importDTO.getBuildName(), importDTO.getUnitName(), importDTO.getHouseNumber());

            ChargeHouseConfig houseConfig = dbHouseList.stream().filter(h ->
                    h.getCommunityName().equals(importDTO.getCommunityName()) && h.getMergeName().equals(importDTO.getHouseNumber())
                            && h.getBuildName().equals(importDTO.getBuildName())).findFirst().orElse(null);
            if(null == houseConfig){
                errorMsg.append(String.format("第%s行,房屋地址和住户信息系统中匹配不到.\n", index));
                i.remove();
                continue;
            }

            ChargeTypeTemp type = dbFeeTypeList.stream().filter(d -> d.getFeeTypeName().equals(importDTO.getFeeTypeName()))
                    .findFirst().orElse(null);

            //获取手机号对应的业主类型
            Map<String, Object> residentMap = residentList.stream().filter(r ->
                    r.get("mobile").toString().trim().equals(importDTO.getMobile())).findFirst().orElse(null);

            if(!Objects.isEmpty(residentMap)){
                billInterim.setChargeName(residentMap.get("realName").toString());
            }

            billInterim.setFeeTypeNo(type.getId());
            billInterim.setCommunityNo(houseConfig.getCommunityNo());
            billInterim.setHouseNo(houseConfig.getHouseNo());
            String billNo = CommonUtil.generateRandom("SF");
            billInterim.setInterimBillNo(billNo);
            billInterim.setBillStatus(ChargeBillStatusEnum.getEnum(importDTO.getBillStatus()));
            billInterim.setBillAddress(address);
            billInterim.setCreateName(username);
            billInterim.setDepartmentNo(departmentNo);
            billInterim.setDepartmentNos(departmentNos);
            billInterim.setDepartmentName(departmentName);

            ormList.add(billInterim);
        }
        int successCount = jdbcSession.insert(ormList).length;
        return excelTool.R(importTotal,successCount,errorMsg.toString());
    }


    private ImportResult getImportResult(List<InterimBillImportDTO> dtoList, int importTotal, StringBuilder errorMsg, List<Integer> errorIndex) {
        dtoList.removeIf(d->errorIndex.contains(d.getIndex()));
        if(Objects.isEmpty(dtoList)){
            return excelTool.R(importTotal,0, errorMsg.toString());
        }
        return null;
    }



    @Override
    public List<ChargeBillInterim> findList(JSONObject jsonObject) {
        return jdbcSession.findArray(ChargeBillInterim.class)
                .eq("deleted", false)
                .eq(jsonObject,"communityNo")
                .eq(jsonObject,"communityName")
                .eq(jsonObject,"houseNo")
                .eq(jsonObject,"billYearMonth")
                .eq(jsonObject,"userNo")
                .eq(jsonObject,"billStatus")
                .eq(jsonObject,"feeTypeNo")
                .order("createTime","desc")
                .exe();
    }

    @Override
    public Object save(ChargeBillInterim chargeBillInterim) throws Exception {

        //保存年月
        String yearMonth = new SimpleDateFormat("yyyy-MM").format(new Date());
        chargeBillInterim.setBillYearMonth(yearMonth);
        chargeBillInterim.setBillStatus(ChargeBillStatusEnum.BILL_WAIT_PAID);
        chargeBillInterim.setChargeStatus(ChargeBillStatusEnum.BILL_UN_PAID);
        chargeBillInterim.setPayableAmount(chargeBillInterim.getBillAmount());
        chargeBillInterim.setBillAddress(chargeBillInterim.getCommunityName());

        //获取手机号对应的业主类型
        if(!Objects.isEmpty(chargeBillInterim.getMobile())){
            Set<String> mobile = new HashSet(Arrays.asList(chargeBillInterim.getMobile()));
            List<Map<String, Object>> resident = commonClient.getResidentListByMobiles(mobile);
            if(!Objects.isEmpty(resident) ){
                chargeBillInterim.setChargeName(resident.get(0).get("realName").toString());
                chargeBillInterim.setUserNo(resident.get(0).get("residentNo").toString());
            }
        }

        commonService.insetLogger(chargeBillInterim.getInterimBillNo(),
                ChargeLogEnum.LOG_CHARGE_BILL_INT.getDesc(),
                "添加临时账单",
                ChargeBillStatusEnum.BILL_WAIT_PAID.getDesc(),
                ChargeBillStatusEnum.BILL_UN_PAID.getDesc(), "添加临时缴费！", chargeBillInterim.getCreateName());

        return jdbcSession.insert(chargeBillInterim);
    }

    @Override
    public Object update(ChargeBillInterim chargeBillInterim) {

        //临时账单作废
        chargeBillInterim.setBillStatus(ChargeBillStatusEnum.BILL_PAID_CLOSE);
        jdbcSession.updateById(chargeBillInterim);

        /** 编号，模块，功能，账单状态，状态，说明，操作人 */
        return commonService.insetLogger(chargeBillInterim.getInterimBillNo(),
                ChargeLogEnum.LOG_CHARGE_BILL_INT.getDesc(),
                "临时账单作废",
                ChargeBillStatusEnum.BILL_PAID_CLOSE.getDesc(),
                ChargeBillStatusEnum.BILL_UN_PAID.getDesc(), "操作成功！", chargeBillInterim.getUpdateName());
    }

    @Override
    public Object deleteById(String id) {
        ChargeBillInterim result = Pool.get(ChargeBillInterim.class, id);
        if (result != null) {
            result.setDeleted(true);
            jdbcSession.updateById(result);
        }
        return 1;
    }

    @Override
    public List<ChargeStatistDTO> findStatist(JSONObject jsonObject) throws Exception {

        List<ChargeStatistDTO> statList = new ArrayList<>();

        return statList;
    }

    @Override
    public Object cancelInterimBill(JSONObject jsonObject, Token token) {

        JSONArray jsonArray = jsonObject.getJSONArray("interimBillNos");

        for (int i = 0; i < jsonArray.size(); i++) {

            String billNo = jsonArray.get(i).toString();
            //1、查询对应的小区
            ChargeBillInterim community = jdbcSession.findOne(ChargeBillInterim.class)
                    .eq("interimBillNo", billNo).exe();

            //2、判断小区下面账单是否有缴费，有缴费则操作失败
            if (ChargeBillStatusEnum.BILL_WAIT_PAID.equals(community.getBillStatus())) {

                community.setBillStatus(ChargeBillStatusEnum.BILL_PAID_CLOSE);
                community.setUpdateName(token.getUsername());
                community.setUpdateTime(TimeUtil.timestamp());
                //3、数据作废
                jdbcSession.updateById(community);
            }

            commonService.insetLogger(billNo,
                    ChargeLogEnum.LOG_CHARGE_BILL_INT.getDesc(),
                    "临时账单作废",
                    ChargeBillStatusEnum.BILL_PAID_CLOSE.getDesc(),
                    ChargeBillStatusEnum.BILL_UN_PAID.getDesc(), "作废账单（备注内容："+billNo+"）", token.getUsername());
        }

        return Result.success();
    }

    @Override
    public Object receiveMoney(JSONObject jsonObject) {
        return null;
    }

    @Override
    public Object getObj(JSONObject jsonObject) {

        return jdbcSession.findOne(ChargeBillInterim.class).eq(jsonObject,"interimBillNo").exe();
    }


}
